package gridy.fitness;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;
import org.osoa.sca.annotations.EagerInit;
import org.osoa.sca.annotations.Init;
import org.osoa.sca.annotations.Property;
import org.osoa.sca.annotations.Reference;
import org.osoa.sca.annotations.Scope;

@EagerInit
@Scope("COMPOSITE")
public class FitnessCalculatorWorkerImpl implements FitnessCalculatorWorker {
    
    static Logger log = Logger.getLogger(FitnessCalculatorWorkerImpl.class);
    
    private String hostname;
    
    @Reference
    protected FitnessCalculatorMaster master;
    
    @Property
    protected int port;
    
    @Init
    public void init() {
        
        // obieranie adresu hosta
        try {
            InetAddress addr = InetAddress.getLocalHost();   
            hostname = addr.getHostName();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
        
        connectWithMaster();
    }
    
    private void connectWithMaster() {
        
        log.info("Rejestrowanie sie u mastera, moj hostname = "+hostname+":"+port);
        master.register(hostname+":"+port);
    }
    
    
    public void unregister() {
        
        log.info("Wyrejestrowuje sie u mastera, moj hostname = "+hostname+":"+port);
        master.unregister(hostname+":"+port);
    }
    
    /**
     * Rastrigin function
     * @param genes
     * @return
     */
    private double getValue(double[] genes) {
        //System.out.println("getValue, genes.length = "+genes.length);
        double value = 10.0 * genes.length;
        for (int i = 0; i < genes.length; i++) {
            value = value + Math.pow(genes[i], 2.0) - 10.0 * Math.cos(2.0 * Math.PI * genes[i]);
        }
        return value;
    }

    @Override
    public void calculate(double[] arguments, int numOfProblems, int firstProblemIndex) {
        
        log.debug("Calculate wywołany, arguments.length = "+arguments.length
                +", numOfProblems = "+numOfProblems
                +", firstProblemIndex = "+firstProblemIndex);
        
        assert arguments.length % numOfProblems == 0;
        int problemSize = arguments.length / numOfProblems;
        double[] results = new double[numOfProblems];
        
        for (int i = 0; i < numOfProblems; i++) {
            
            double[] problem = new double[problemSize];
            for (int j = 0; j < problemSize; j++) {
               problem[j] = arguments[(i * problemSize) + j];
            }
            
            // dla testów liczy 1000 razy to samo
            for (int j = 0; j < 100; j++) {
                results[i] = getValue(problem);
            }
            
        }
        master.putResults(results, firstProblemIndex);
        
    }
}
